﻿using System;
using System.Collections.Generic;
using System.Text;

using Uber.Storage;
using Uber.Messages;
using Uber.HabboHotel.GameClients;
using Uber.HabboHotel.Pathfinding;
using Uber.HabboHotel.RoomBots;
using Uber.HabboHotel.Misc;
using Uber.HabboHotel.Pets;
using Uber.Collections;

namespace Uber.HabboHotel.Rooms
{
    class RoomUser
    {
        public uint HabboId;
        public int VirtualId;
        public uint RoomId;

        public int IdleTime;

        private int MessageCount;
        private DateTime MessageTime;

        public int X;
        public int Y;
        public double Z;

        public int CarryItemID;
        public int CarryTimer;

        public int RotHead;
        public int RotBody;

        public bool CanWalk;
        public bool WalkBackwards;
        public bool TeleportMode;
        public bool AllowOverride;

        public int GoalX;
        public int GoalY;

        public Boolean SetStep;
        public int SetX;
        public int SetY;
        public double SetZ;

        public RoomBot BotData;
        public BotAI BotAI;

        public Coord Coordinate
        {
            get
            {
                return new Coord(X, Y);
            }
        }

        public bool IsPet
        {
            get
            {
                return (IsBot && BotData.IsPet);
            }
        }

        public Pet PetData;

        public Boolean IsWalking;
        public Boolean UpdateNeeded;
        public Boolean IsAsleep;

        public Dictionary<string, string> Statusses;

        public int DanceId;

        public List<PathFinderNode> Path;
        public int PathStep;

        public bool PathRecalcNeeded;
        public int PathRecalcX;
        public int PathRecalcY;

        public int TeleDelay;

        public Boolean IsDancing
        {
            get
            {
                return (DanceId >= 1);
            }
        }

        public Boolean HasItemEffect
        {
            get
            {
                return (GetRoom().UserEffects.ContainsKey(HabboId));
            }
        }

        public int GetItemEffect
        {
            get
            {
                if (HasItemEffect)
                {
                    return GetRoom().UserEffects[HabboId];
                }
                else
                {
                    return 0;
                }
            }
        }

        public Boolean NeedsAutokick
        {
            get
            {
                return (!IsBot && IdleTime >= 1800);
            }
        }

        public bool IsTrading
        {
            get
            {
                return (!IsBot && Statusses.ContainsKey("trd"));
            }
        }

        public bool IsBot
        {
            get
            {
                return (this.BotData != null);
            }
        }

        public bool IsSpectator;

        public RoomUser(uint mHabboId, uint mRoomId, int mVirtualId)
        {
            this.HabboId = mHabboId;
            this.RoomId = mRoomId;
            this.VirtualId = mVirtualId;
            this.IdleTime = 0;
            this.X = 0;
            this.Y = 0;
            this.Z = 0;
            this.RotHead = 0;
            this.RotBody = 0;
            this.UpdateNeeded = true;

            this.Statusses = new Dictionary<string, string>();
            this.Path = new List<PathFinderNode>();

            this.PathStep = 0;
            this.TeleDelay = -1;

            // Start Booleans
            this.AllowOverride = false;
            this.WalkBackwards = false;
            this.TeleportMode = false;
            this.CanWalk = true;
            this.IsSpectator = false;
            // End Booleans
        }

        public void Unidle()
        {
            this.IdleTime = 0;

            if (this.IsAsleep)
            {
                this.IsAsleep = false;

                ServerMessage Message = new ServerMessage(486);
                Message.AppendInt32(VirtualId);
                Message.AppendBoolean(false);

                GetRoom().SendMessage(Message);
            }
        }

        public void Chat(GameClient Session, string Message, bool Shout)
        {
            this.Unidle();

            if (!IsBot && GetRoom().IsMuted && Session.GetHabbo().Rank <= 1)
            {
                return;
            }

            if (!IsBot)
            {
                if (!Session.GetHabbo().ExpiredBan) // expired chatban
                {
                    TimeSpan Diff = (DateTime.Now - Session.GetHabbo().MutedTime);
                    Session.SendNotif("Your ban expire in: " + (5 - (int)Diff.TotalMinutes) + " Minutes.");
                    return;
                }
            }

            if (Message.Length < 0)
            {
                return;
            }

            if (!IsBot && GetClient().GetHabbo().Muted)
            {
                GetClient().SendNotif("You are muted.");
                return;
            }

            if (!IsBot)
            {
                string Lowered = Message.ToLower();
                Lowered = Lowered.Replace(" ", "");
                Lowered = Lowered.Replace("´", "");
                Lowered = Lowered.Replace("`", "");
                Lowered = Lowered.Replace("^", "");
                Lowered = Lowered.Replace("*", "");
                Lowered = Lowered.Replace("'", "");
                Lowered = Lowered.Replace("-", "");


                Message = UberEnvironment.GetGame().GetChatWordFilter().CheckWords(Message, Session);


                if (Lowered.Contains("forcehotel") || Lowered.Contains("skez") || Lowered.Contains("debbo") || Lowered.Contains("debbohotel") || Lowered.Contains("habbohotel") || Lowered.Contains("rabbohotel") || Lowered.Contains("noobhotel") || Lowered.Contains("fobbahotel.nl") || Lowered.Contains("fobbahotel") || Lowered.Contains("*********") || Lowered.Contains("demonhotel") || Lowered.Contains("clanhabbo") || Lowered.Contains("vortexhotel") || Lowered.Contains("habbzone") || Lowered.Contains("rainhotel") || Lowered.Contains("edhotel") || Lowered.Contains("elite-royale") || Lowered.Contains("hotelnine") || Lowered.Contains("ajhotel") || Lowered.Contains("hectichotel") || Lowered.Contains("hablex") || Lowered.Contains("nova-space") || Lowered.Contains("harbohotel") || Lowered.Contains("flexhotel") || Lowered.Contains("rabbohotel") || Lowered.Contains("blizzardhotel") || Lowered.Contains("blahhotel"))
                {
                    GetClient().SendNotif("Advertising is strictly prohibited. Our chatlogs are monitored daily by moderators, and if you advertise you will get caught and IP banned.");
                    return;
                }

                TimeSpan SinceLastMessage = DateTime.Now - MessageTime;

                if (SinceLastMessage.Seconds > 4)
                {
                    MessageCount = 0;
                }
                if (SinceLastMessage.Seconds < 4 && MessageCount > 6)
                {
                    ServerMessage Packet = new ServerMessage(27);
                    Packet.AppendInt32(30);
                    GetClient().SendMessage(Packet);
                    return;
                }

                MessageTime = DateTime.Now;
                MessageCount++;
            }

            if (!IsBot && Message.StartsWith(":") && Session != null && ChatCommandHandler.Parse(Session, Message.Substring(1)))
            {
                return;
            }

            uint ChatHeader = 24;

            if (Shout)
            {
                ChatHeader = 26;
            }

            string Site = "";

            ServerMessage ChatMessage = new ServerMessage(ChatHeader);
            ChatMessage.AppendInt32(VirtualId);

            if (Message.Contains("http://") || Message.Contains("www."))
            {
                string[] Split = Message.Split(' ');

                foreach (string Msg in Split)
                {
                    if (Msg.StartsWith("http://") || Msg.StartsWith("www."))
                    {
                        Site = Msg;
                        Message = Message.Replace(Site, "{0}");
                    }
                }
            }

            ChatMessage.AppendStringWithBreak(Message);

            if (Site != "")
            {
                ChatMessage.AppendBoolean(false);
                ChatMessage.AppendBoolean(true);
                ChatMessage.AppendStringWithBreak(Site.Replace("http://", ""));
                ChatMessage.AppendStringWithBreak(Site);
            }

            ChatMessage.AppendInt32(GetSpeechEmotion(Message));
            ChatMessage.AppendBoolean(false);

            GetRoom().TurnHeads(X, Y, HabboId);

            if (!IsBot)
            {
                for(int i = 0; i < GetRoom().UserList.Count; i++)
                {
                    RoomUser User = GetRoom().UserList[i]; if (User == null) { continue; }

                    if (User.IsBot || User.IsPet || User.GetClient() == null)
                    {
                        continue; // skip these users
                    }

                    if (User.GetClient().GetHabbo().CurrentQuestId == 3)
                    {
                        UberEnvironment.GetGame().GetQuestManager().UpdateQuest(3, User.GetClient());
                    }

                    if (!User.GetClient().GetHabbo().MutedUsers.Contains(Session.GetHabbo().Id))
                    {
                        User.GetClient().SendMessage(ChatMessage);
                    }
                }
            }
            else
            {
                GetRoom().SendMessage(ChatMessage);
            }

            if (!IsBot)
            {
                GetRoom().OnUserSay(this, Message, Shout);
            }

            if (!IsBot)
            {
                UberEnvironment.GetGame().GetChatlogsManager().AddChatlog(Session.GetHabbo().Id, GetRoom().RoomId, DateTime.Now.Hour, DateTime.Now.Minute, UberEnvironment.GetUnixTimestamp(), Message, Session.GetHabbo().Username, DateTime.Now.ToLongDateString());

                /*using (DatabaseClient dbClient = UberEnvironment.GetDatabase().GetClient())
                {
                    dbClient.AddParamWithValue("message", Message);
                    dbClient.ExecuteQuery("INSERT INTO chatlogs (user_id,room_id,hour,minute,timestamp,message,user_name,full_date) VALUES ('" + Session.GetHabbo().Id + "','" + GetRoom().RoomId + "','" + DateTime.Now.Hour + "','" + DateTime.Now.Minute + "','" + UberEnvironment.GetUnixTimestamp() + "',@message,'" + Session.GetHabbo().Username + "','" + DateTime.Now.ToLongDateString() + "')");
                }*/
            }
        }

        public int GetSpeechEmotion(string Message)
        {
            Message = Message.ToLower();

            if (Message.Contains(":)") || Message.Contains(":d") || Message.Contains("=]") || 
                Message.Contains("=d") || Message.Contains(":>") || Message.Contains(":]") ||
                Message.Contains("(;") || Message.Contains("(:"))
            {
                return 1;
            }

            if (Message.Contains(">:(") || Message.Contains(":@") || Message.Contains(">:["))
            {
                return 2;
            }

            if (Message.Contains(":o") || Message.Contains(";o"))
            {
                return 3;
            }

            if (Message.Contains(":(") || Message.Contains("=[") || Message.Contains(":'(") || Message.Contains("='["))
            {
                return 4;
            }

            return 0;
        }

        public void ClearMovement(bool Update)
        {
            IsWalking = false;
            PathRecalcNeeded = false;

            this.Path = null;
            this.Path = new List<PathFinderNode>();

            if (this.Statusses.ContainsKey("mv")) { Statusses.Remove("mv"); }

            GoalX = 0;
            GoalY = 0;
            SetStep = false;
            SetX = 0;
            SetY = 0;
            SetZ = 0;

            if (Update) { UpdateNeeded = true; }
        }

        public void MoveTo(Coord c)
        {
            MoveTo(c.x, c.y);
        }

        public void MoveTo(int X, int Y)
        {
            Unidle();

            if (X > GetRoom().Model.MapSizeX || Y > GetRoom().Model.MapSizeY)
            {
                this.GetClient().SendNotif("You can't walk out of the map!");
                return;
            }

            if (TeleportMode)
            {
                //UberEnvironment.GetGame().GetRoomManager().GetRoom(RoomId).UserMatrix[this.X, this.Y] = false;
                this.X = X;
                this.Y = Y;
                UpdateNeeded = true;
            }
            else
            {
                PathRecalcX = X;
                PathRecalcY = Y;
                PathRecalcNeeded = true;
            } 
        }

        public void UnlockWalking()
        {
            this.AllowOverride = false;
            this.CanWalk = true;
        }

        public void SetPos(int X, int Y, double Z)
        {
            this.X = X;
            this.Y = Y;
            this.Z = Z;
        }

        public void CarryItem(int Item)
        {
            this.CarryItemID = Item;

            if (Item > 0)
            {
                this.CarryTimer = 240;
            }
            else if (Item <= 0)
            {
                this.CarryTimer = 0;
            }

            ServerMessage Message = new ServerMessage(482);
            Message.AppendInt32(VirtualId);
            Message.AppendInt32(Item);
            GetRoom().SendMessage(Message);
        }

        public void SetRot(int Rotation)
        {
            SetRot(Rotation, false);
        }

        public void SetRot(int Rotation, bool HeadOnly)
        {
            if (Statusses.ContainsKey("lay") || IsWalking)
            {
                return;
            }

            int diff = this.RotBody - Rotation;

            this.RotHead = this.RotBody;

            if (Statusses.ContainsKey("sit") || HeadOnly)
            {
                if (RotBody == 2 || RotBody == 4)
                {
                    if (diff > 0)
                    {
                        RotHead = RotBody - 1;
                    }
                    else if (diff < 0)
                    {
                        RotHead = RotBody + 1;
                    }
                }
                else if (RotBody == 0 || RotBody == 6)
                {
                    if (diff > 0)
                    {
                        RotHead = RotBody - 1;
                    }
                    else if (diff < 0)
                    {
                        RotHead = RotBody + 1;
                    }
                }
            }
            else if (diff <= -2 || diff >= 2)
            {
                this.RotHead = Rotation;
                this.RotBody = Rotation;
            }
            else
            {
                this.RotHead = Rotation;
            }

            this.UpdateNeeded = true;
        }

        public void AddStatus(string Key, string Value)
        {
            Statusses[Key] = Value;

            UpdateNeeded = true;
        }

        public void RemoveStatus(string Key)
        {
            if (Statusses.ContainsKey(Key))
            {
                Statusses.Remove(Key);
            }
        }

        public void ResetStatus()
        {
            this.Statusses = null;
            this.Statusses = new Dictionary<string, string>();
        }

        public void Serialize(ServerMessage Message)
        {
            // @\Ihqu@UMeth0d13haiihr-893-45.hd-180-8.ch-875-62.lg-280-62.sh-290-62.ca-1813-.he-1601-[IMRAPD4.0JImMcIrDK
            // MSadiePull up a pew and have a brew!hr-500-45.hd-600-1.ch-823-75.lg-716-76.sh-730-62.he-1602-75IRBPA2.0PAK

            if (IsSpectator)
            {
                return;
            }

            if (!IsBot)
            {
                //Message.AppendBoolean(true);
                Message.AppendUInt(GetClient().GetHabbo().Id);
                Message.AppendStringWithBreak(GetClient().GetHabbo().Username);
                Message.AppendStringWithBreak(GetClient().GetHabbo().Motto);
                Message.AppendStringWithBreak(GetClient().GetHabbo().Look.ToLower());
                Message.AppendInt32(VirtualId);
                Message.AppendInt32(X);
                Message.AppendInt32(Y);
                Message.AppendStringWithBreak(Z.ToString().Replace(',', '.'));
                Message.AppendInt32(2);
                Message.AppendInt32(1);
                Message.AppendStringWithBreak(GetClient().GetHabbo().Gender.ToLower());
                Message.AppendInt32(-1);
                Message.AppendInt32(-1);
                Message.AppendInt32(-1);
                Message.AppendBreak();
                Message.AppendInt32(GetClient().GetHabbo().GetAchievementScore()); // R63 Room User change for achievement score!
            }
            else
            {
                //btmFZoef0 008 D98961JRBQA0.0PAJH
                Message.AppendUInt(PetData.PetId);
                Message.AppendStringWithBreak(BotData.Name);
                Message.AppendStringWithBreak(BotData.Motto);
                Message.AppendStringWithBreak((IsPet) ? PetData.Look : BotData.Look);
                Message.AppendInt32(VirtualId);
                Message.AppendInt32(X);
                Message.AppendInt32(Y);
                Message.AppendStringWithBreak(Z.ToString().Replace(',', '.'));
                Message.AppendInt32(4);
                Message.AppendInt32((BotData.AiType.ToLower() == "pet") ? 2 : 3);

                if (BotData.AiType.ToLower() == "pet")
                {
                    Message.AppendInt32(11);
                }
            }
        }

        public void SerializeStatus(ServerMessage Message)
        {
            if (IsSpectator)
            {
                return;
            }

            Message.AppendInt32(VirtualId);
            Message.AppendInt32(X);
            Message.AppendInt32(Y);
            Message.AppendStringWithBreak(Z.ToString().Replace(',','.'));
            Message.AppendInt32(RotHead);
            Message.AppendInt32(RotBody);
            Message.AppendString("/");

            if (!IsPet)
            {
                foreach (KeyValuePair<string, string> Status in Statusses)
                {
                    Message.AppendString(Status.Key);
                    Message.AppendString(" ");
                    Message.AppendString(Status.Value);
                    Message.AppendString("/");
                }

                Message.AppendStringWithBreak("/");
            }
            else if (IsPet)
            {
                if (Statusses.Count == 0)
                {
                    Message.AppendString("/");
                }

                foreach (KeyValuePair<string, string> Status in Statusses)
                {
                    Message.AppendString("/");
                    Message.AppendString(Status.Key);
                }

                Message.AppendBreak();
            }


            Console.WriteLine(Message);
        }

        public GameClient GetClient()
        {
            if (IsBot)
            {
                return null;
            }

            return UberEnvironment.GetGame().GetClientManager().GetClientByHabbo(HabboId);
        }

        private Room GetRoom()
        {
            return UberEnvironment.GetGame().GetRoomManager().GetRoom(RoomId);
        }
    }
}
